const request = require('request-promise')
const requestAsync = require('async-request')
const REDIS = require('./util.redis')
const CONFIG = require('./util.config') // 配置地址文件
// console.log(REDIS)
REDIS.setRedis('yezi_jsapi_ticket', 'ex', 1)
REDIS.setRedis('yezi_access_token', 'ex', 1)

const schedule = require('node-schedule') // 定时任务

let createNonceStr = function () {
  return Math.random().toString(36).substr(2, 15)
}

let createTimestamp = function () {
  return parseInt(new Date().getTime() / 1000) + ''
}
/**
 * @synopsis 签名算法
 * @param jsapi_ticket 用于签名的 jsapi_ticket
 * @param url 用于签名的 url ，注意必须动态获取，不能 hardcode
 * @returns
 */
async function sign (ticket, url) {
  let ret = {
    jsapi_ticket: ticket,
    noncestr: createNonceStr(),
    timestamp: createTimestamp(),
    url: url
  }
  let string = await raw(ret)
  const JsSHA = require('./sha')
  let shaObj = new JsSHA(string, 'TEXT')
  ret.signature = shaObj.getHash('SHA-1', 'HEX')
  return ret
}
// 创建菜单 强制刷新token
async function createMenu () {
  let accessToken = await getAccesstoken() // await REDIS.getRedis('yezi_access_token') //
  let url = `https://open.weixin.qq.com/connect/oauth2/authorize?appid=${CONFIG.appid}&redirect_uri=${CONFIG.domain}&response_type=code&scope=snsapi_base&state=base#wechat_redirect`
  let opts = {
    url: `https://api.weixin.qq.com/cgi-bin/menu/create?access_token=${accessToken}`,
    method: 'post',
    body: JSON.stringify({
      'button': [{
        'type': 'view',
        'name': '今日预测',
        'url': url
      }, {
        'type': 'miniprogram',
        'name': '轻松视频',
        'url': url,
        'appid': 'wx0fb78ce64154f8eb',
        'pagepath': '/page/index/index'
      }, {
        'type': 'miniprogram',
        'name': '我',
        'url': url,
        'appid': 'wx8ee31bfd8e136bd8',
        'pagepath': '/page/comp/user/user'
      }]
    })
  }
  request(opts).then(res => { console.log(res) })
}
// 获取JsapiTicket
async function getJsapiTicket () {
  let token = await REDIS.getRedis('yezi_access_token')
  let ticket
  if (token) {
    ticket = await getTicket(token)
    // 获取ticket
    return ticket
  } else {
    let accessToken = await getAccesstoken()
    ticket = await getTicket(accessToken)
    return ticket
  }
}
// 获取 ticket
async function getTicket (token) {
  let body
  let url = `https://api.weixin.qq.com/cgi-bin/ticket/getticket?access_token=${token}&type=jsapi`
  await request(url)
  .then(res => {
    body = JSON.parse(res)
    console.log('get ticket from wexin result: ', body)
  }).catch((err) => {
    console.error('请求微信ticket出错', err)
  })

  if (body.errcode === 42001 || body.errcode === 40001) {
    oneMoreTime()
  } else {
    REDIS.setRedis('yezi_jsapi_ticket', body.ticket, 7100)
    return body
  }
}
// 获取accsee_token 并重新获取 tiket
async function oneMoreTime () {
  let token = await getAccesstoken()
  getTicket(token)
}
// 获取普通 accesstoken
async function getAccesstoken () {
  let body
  let url = `https://api.weixin.qq.com/cgi-bin/token?grant_type=client_credential&appid=${CONFIG.appid}&secret=${CONFIG.appsecret}`
  await request(url)
  .then(res => {
    body = JSON.parse(res)
    if (body.errcode !== 45009) {
      console.log('get accesstoken from weixin: ', body)
      REDIS.setRedis('yezi_access_token', body.access_token, 7150)
      updatetAccesstoken(30)
    } else {
      throw new Error(`get access token error from wexin: ${body.errcode}`)
    }
  })
  return body.access_token
}
// 定时任务,每小时运行一次
async function updatetAccesstoken (time) {
  let rule = new schedule.RecurrenceRule()
  rule.minute = time
  schedule.scheduleJob(rule, () => {
    getAccesstoken(null, () => {
      console.log('scheduleJob doing and update access_token', new Date())
    })
  })
}

// 预支付接口
async function prePay (req) {
  const url = 'https://api.mch.weixin.qq.com/pay/unifiedorder'
  let formData = '<xml>'
  let prepayIdTmp, nonceStrTmp
  formData += '<appid>' + req.appid + '</appid>' // appid
  formData += '<body>' + req.body + '</body>' // 商品或支付单简要描述
  formData += '<device_info>' + req.device_info + '</device_info>' // 硬件信息
  formData += '<mch_id>' + req.mch_id + '</mch_id>' // 商户号
  formData += '<nonce_str>' + req.nonce_str + '</nonce_str>' // 随机字符串，不长于32位
  formData += '<notify_url>' + req.notify_url + '</notify_url>' // 支付成功后微信服务器通过POST请求通知这个地址
  formData += '<openid>' + req.openid + '</openid>'
  formData += '<out_trade_no>' + req.out_trade_no + '</out_trade_no>' // 订单号
  formData += '<spbill_create_ip>' + req.spbill_create_ip + '</spbill_create_ip>' //
  formData += '<total_fee>' + req.total_fee + '</total_fee>' // 金额
  formData += '<trade_type>' + req.trade_type + '</trade_type>' // NATIVE会返回code_url ，JSAPI不会返回
  formData += '<sign>' + req.sign + '</sign>'
  formData += '</xml>'

  let res = await requestAsync(url, { method: 'POST', data: formData })

  console.log('unifiedorder: ', res)
  if (res.statusCode === 200) {
    console.log(res.body)
  } else {
    console.error(res)
  }
  // prepay_id
  let prepayId = await getXMLNodeValue('prepay_id', res.body.toString('utf-8'))
  let tmp = prepayId.split('[')
  prepayIdTmp = tmp[2].split(']')
  // nonce_str
  let nonceStr = await getXMLNodeValue('nonce_str', res.body.toString('utf-8'))
  let tmp2 = nonceStr.split('[')
  nonceStrTmp = tmp2[2].split(']')
  console.log(prepayIdTmp, nonceStrTmp)
  return {
    prepay_id: prepayIdTmp[0],
    nonce_str: nonceStrTmp[0]
  }
}
// 支付签名
async function paysign (req, key) {
  var string = await raw(req)
  string = string + '&key=' + key // key为在微信商户平台(pay.weixin.qq.com)-->账户设置-->API安全-->密钥设置
  const crypto = require('crypto')
  return crypto.createHash('md5').update(string, 'utf8').digest('hex').toUpperCase()
}

// 随机数
async function randomString (length) {
  const chars = 'ABCDEFGHJKMNPQRSTWXYZabcdefhijkmnprstwxyz2345678' /** **默认去掉了容易混淆的字符oOLl,9gq,Vv,Uu,I1****/
  let maxPos = chars.length
  let pwd = ''
  for (var i = 0; i < length; i++) {
    pwd += chars.charAt(Math.floor(Math.random() * maxPos))
  }
  return pwd
}

async function raw (args) {
  var keys = Object.keys(args)
  keys = keys.sort()
  var newArgs = {}
  keys.forEach(function (key) {
    newArgs[key] = args[key]
  })

  var string = ''
  for (var k in newArgs) {
    string += '&' + k + '=' + newArgs[k]
  }
  string = string.substr(1)
  return string
}

async function getXMLNodeValue (nodeName, xml) {
  let node = nodeName
  try {
    let tmp = xml.split('<' + node + '>')
    let _tmp = tmp[1].split('</' + node + '>')
    return _tmp[0]
  } catch (err) {
    console.log(err)
    return '[error]'
  }
}

module.exports = {
  sign, getJsapiTicket, createMenu, paysign, randomString, prePay
}
